﻿using System;


namespace Sencha.Serialization.Bson
{
	/// <summary>
	/// Timestamps are stored as 64 bit values which, on a single mongod, are guaranteed unique. The first 32 bits are a time_t value (seconds since the UTC epoch). 
	/// The second 32 bits are an incrementing ordinal for operations within a given second.
	/// http://www.mongodb.org/display/DOCS/Timestamp+data+type
	/// </summary>
	[TypeSerializer(typeof(Serializers.BsonTimestampSerializer))]
	public struct BsonTimestamp : IEquatable<BsonTimestamp>, IComparable, IComparable<BsonTimestamp>
	{
		private long timeStamp;

		public long Raw { get { return this.timeStamp; } }

		public uint Seconds { get { return (uint)(this.timeStamp & uint.MaxValue); } }
		public uint Increment { get { return (uint)(this.timeStamp >> 32); } }

		public BsonTimestamp(long timeStamp)
		{
			this.timeStamp = timeStamp;
		}

		#region IEquatable<BsonTimestamp> Members

		public override bool Equals(object obj)
		{
			if (obj is BsonTimestamp)
				return this.Equals((BsonTimestamp)obj);
			return false;
		}

		public override int GetHashCode()
		{
			return this.timeStamp.GetHashCode();
		}

		public bool Equals(BsonTimestamp other)
		{
			return this.timeStamp == other.timeStamp;
		}

		#endregion
		#region IComparable Members

		public int CompareTo(object obj)
		{
			if (obj is BsonTimestamp)
				return this.CompareTo((BsonTimestamp)obj);

			return 1;
		}

		#endregion
		#region IComparable<BsonTimestamp> Members

		public int CompareTo(BsonTimestamp other)
		{
			var cmp = this.Seconds.CompareTo(other.Seconds);
			if (cmp == 0)
				return this.Increment.CompareTo(other.Increment);
			return cmp;
		}

		#endregion

		public static bool operator >(BsonTimestamp a, BsonTimestamp b)
		{
			return a.CompareTo(b) == 1;
		}
		public static bool operator <(BsonTimestamp a, BsonTimestamp b)
		{
			return a.CompareTo(b) == -1;
		}
		public static bool operator >=(BsonTimestamp a, BsonTimestamp b)
		{
			return a.CompareTo(b) != -1;
		}
		public static bool operator <=(BsonTimestamp a, BsonTimestamp b)
		{
			return a.CompareTo(b) != 1;
		}
		public static bool operator ==(BsonTimestamp a, BsonTimestamp b)
		{
			return a.timeStamp == b.timeStamp;
		}
		public static bool operator !=(BsonTimestamp a, BsonTimestamp b)
		{
			return a.timeStamp != b.timeStamp;
		}
		public static implicit operator BsonTimestamp(long value)
		{
			return new BsonTimestamp(value);
		}
		public static explicit operator long(BsonTimestamp value)
		{
			return value.timeStamp;
		}

		public override string ToString()
		{
			return string.Format("timestamp: {0}, inc: {1}", BsonDateTime.Epoch.AddSeconds(this.Seconds), this.Increment);
		}
	}
}
